﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace MyVideoViewerLibrary.MyMoviesXML
{
    public class MyMoviesXMLBusiness : IMoviesBusiness
    {
        string[] extensions = new string[] { ".mov", ".avi", ".mpeg", ".mpg", ".mkv", ".wmv", ".mp4", ".dvr-ms", ".m2ts", ".ts", ".divx" };
        private List<Movie> movies;
        private List<Genre> genres;
        private List<Studio> studios;
        public List<Generic> categories;
        public List<Generic> mpaaRatings;

        public MyMoviesXMLBusiness()
        {
            genres = new List<Genre>();
            movies = new List<Movie>();
            studios = new List<Studio>();
            categories = new List<Generic>();
            mpaaRatings = new List<Generic>();

            LoadMovies();
        }

        public void LoadMovies()
        {
            if (!File.Exists(Settings.Default.MyMoviesXmlFile))
                throw new Exception("File does not exist.");

            XDocument doc = XDocument.Load(Settings.Default.MyMoviesXmlFile);
            XElement root = doc.Element("Titles");
            if (root == null)
                return;
            int tempInt;
            DateTime tempDate;

            foreach (XElement xmovie in root.Elements("Title"))
            {
                Movie movie = new Movie()
                    {
                        Title = xmovie.Element("OriginalTitle") != null ? xmovie.Element("OriginalTitle").Value : "",
                        SortTitle = xmovie.Element("SortTitle") != null ? xmovie.Element("SortTitle").Value : "",
                        Description = xmovie.Element("Description") != null ? xmovie.Element("Description").Value : "",
                        IMDBId = xmovie.Element("IMDB") != null ? xmovie.Element("IMDB").Value : "",
                    };

                if (xmovie.Element("RunningTime") != null)
                {
                    if (int.TryParse(xmovie.Element("RunningTime").Value, out tempInt))
                        movie.Runtime = tempInt;
                }

                if (xmovie.Element("Added") != null)
                {
                    if (DateTime.TryParse(xmovie.Element("Added").Value, out tempDate))
                        movie.DateAdded = tempDate;
                }                

                if (xmovie.Element("ParentalRating") != null)
                {
                    XElement parentalRating = xmovie.Element("ParentalRating");
                    if (parentalRating.Element("Value") != null && int.TryParse(parentalRating.Element("Value").Value, out tempInt))
                    {                        
                        movie.MPAARating = MoviesBusiness.GetMPAARatingText((MPAARating)tempInt);
                        Generic mrating = mpaaRatings.SingleOrDefault(m => m.Name == movie.MPAARating);
                        if (mrating == null)
                        {
                            mrating = new Generic(movie.MPAARating);
                            mpaaRatings.Add(mrating);
                        }
                        mrating.Movies.Add(movie);
                    }

                    if (parentalRating.Element("Description") != null)
                        movie.MPAARatingDescription = parentalRating.Element("Description").Value;
                }

                if (xmovie.Element("Added") != null)
                {
                    if (DateTime.TryParse(xmovie.Element("Added").Value, out tempDate))
                        movie.DateAdded = tempDate;
                }

                if (xmovie.Element("ReleaseDate") != null)
                {
                    if (DateTime.TryParse(xmovie.Element("ReleaseDate").Value, out tempDate))
                        movie.ReleaseDate = tempDate;
                }
                XElement localTrailers = xmovie.Element("LocalTrailer");
                if (localTrailers != null && localTrailers.Element("URL") != null && localTrailers.Element("Type") != null)
                {
                    if (int.TryParse(localTrailers.Element("Type").Value, out tempInt))
                    {
                        if(tempInt == 1)
                            movie.Trailer = localTrailers.Element("URL").Value;
                    }
                }

                var q = xmovie.Descendants("Disc").Where(d => d.Element("LocationSideA") != null && !string.IsNullOrEmpty(d.Element("LocationSideA").Value));
                XElement disc1 = q.FirstOrDefault();
                if (disc1 != null)
                {
                    DirectoryInfo folder = new DirectoryInfo(disc1.Element("LocationSideA").Value);
                    if (folder.Exists)
                    {
                        movie.PosterImageLocation = Path.Combine(folder.FullName, "folder.jpg");
                        movie.BackgroundImageLocation = Path.Combine(folder.FullName, "background.jpg");
                    }
                }

                if (xmovie.Element("Genres") != null)
                {
                    foreach (XElement xgenre in xmovie.Element("Genres").Descendants("Genre"))
                    {
                        if (xgenre == null || string.IsNullOrEmpty(xgenre.Value))
                            continue;
                        Genre genre = genres.SingleOrDefault(g => g.GenreDesc == xgenre.Value);
                        if (genre == null)
                        {
                            genre = new Genre() { GenreDesc = xgenre.Value, Movies = new List<Movie>() };
                            genres.Add(genre);
                        }
                        movie.Genres.Add(genre);
                        genre.Movies.Add(movie);
                    }
                }

                if (xmovie.Element("Studios") != null)
                {
                    foreach (XElement xstudio in xmovie.Element("Studios").Descendants("Studio"))
                    {
                        if (xstudio == null || string.IsNullOrEmpty(xstudio.Value))
                            continue;
                        Studio studio = studios.SingleOrDefault(g => g.Name == xstudio.Value);
                        if (studio == null)
                        {
                            studio = new Studio() { Name = xstudio.Value, Movies = new List<Movie>() };
                            studios.Add(studio);
                        }
                        movie.Studios.Add(studio);
                        studio.Movies.Add(movie);
                    }
                }

                if (xmovie.Element("Categories") != null)
                {
                    foreach (XElement xcat in xmovie.Element("Categories").Descendants("Category"))
                    {
                        if (xcat == null || string.IsNullOrEmpty(xcat.Value))
                            continue;
                        Generic category = categories.SingleOrDefault(g => g.Name == xcat.Value);
                        if (category == null)
                        {
                            category = new Generic() { Name = xcat.Value, Movies = new List<Movie>() };
                            categories.Add(category);
                        }
                        category.Movies.Add(movie);
                    }
                }
                XElement persons = xmovie.Element("Persons");
                if (persons != null)
                {

                    IEnumerable<XElement> directors = persons.Elements("Person").Where(p => p.Element("Type") != null && p.Element("Type").Value == "Director");
                    if (directors != null)
                        movie.Director = string.Join(", ", directors.Select(d => d.Element("Name").Value).ToArray());
                }

                movie.OnGetFiles += new GetFilesEvent(movie_OnGetFiles);

                movie.Data = xmovie;
                movies.Add(movie);
            }
        }

        void movie_OnGetFiles(Movie movie)
        {
            XElement xmovie = movie.Data as XElement;
            var discs = xmovie.Descendants("Disc").Where(d => d.Element("LocationSideA") != null && !string.IsNullOrEmpty(d.Element("LocationSideA").Value));
            foreach (XElement disc in discs)
            {
                DirectoryInfo folder = new DirectoryInfo(disc.Element("LocationSideA").Value);
                if (folder.Exists)
                {
                    DirectoryInfo dvdFolder = folder.GetDirectories("VIDEO_TS").FirstOrDefault();
                    if (dvdFolder != null)
                    {
                        movie.Files.Add(dvdFolder.FullName);
                    }

                    foreach (FileInfo file in folder.GetFiles().OrderBy(f => f.Name))
                    {
                        if (Path.GetFileNameWithoutExtension(file.Name) == "trailer" && extensions.Contains(file.Extension))
                        {
                            movie.Trailer = file.FullName;
                            continue;
                        }
                        else if (extensions.Contains(file.Extension))
                        {
                            movie.Files.Add(file.FullName);
                        }
                    }

                }
            }
        }

        #region IMoviesBusiness Members

        public List<Movie> GetMovies()
        {
            return movies;
        }

        public List<CommandItem> GetFilterItems()
        {
            List<CommandItem> filters = new List<CommandItem>();

            filters.Add(new CommandItem("Title", (int)FilterType.Title));
            filters.Add(new CommandItem("Last Added", (int)FilterType.LastAdded));
            filters.Add(new CommandItem("MPAA Rating", (int)FilterType.MPAARating));
            filters.Add(new CommandItem("Genre", (int)FilterType.Genre));
            filters.Add(new CommandItem("Release Date", (int)FilterType.ReleaseDate));
            filters.Add(new CommandItem("Runtime", (int)FilterType.Runtime));

            return filters;
        }

        public List<CommandItem> GetCommandItems()
        {
            List<CommandItem> commandItems = new List<CommandItem>();
            commandItems.Add(new CommandItem("All Titles", 0));
            commandItems.Add(new CommandItem("Categories", 1));
            commandItems.Add(new CommandItem("Genres", 2));
            commandItems.Add(new CommandItem("MPAA Ratings", 3));
            return commandItems;
        }

        public List<CommandItem> GetCommandItems(int id)
        {
            List<CommandItem> commandItems = new List<CommandItem>();
            switch (id)
            {
                case 1:
                    
                    foreach (Generic category in categories.OrderBy(g=>g.Name))
                    {
                        commandItems.Add(new CommandItem(string.Format("{0} ({1})", category.Name, category.Movies.Count), category));
                    }
                    break;
                case 2:

                    foreach (Genre genre in genres.OrderBy(g => g.GenreDesc))
                    {
                        commandItems.Add(new CommandItem(string.Format("{0} ({1})", genre.GenreDesc, genre.Movies.Count), genre));
                    }
                    break;
                case 3:
                    foreach (Generic rating in mpaaRatings.OrderBy(g => g.Name))
                    {
                        commandItems.Add(new CommandItem(string.Format("{0} ({1})", rating.Name, rating.Movies.Count), rating));
                    }
                    break;                
                default:
                    break;
            }


            return commandItems;
        }

        public List<Movie> GetMoviesFromCommand(int commandId, object data)
        {
            switch (commandId)
            {
                case 0:
                    return movies;
                case 1:
                    Generic category = data as Generic;
                    return category.Movies;
                case 2:
                    Genre genre = data as Genre;
                    return genre.Movies;
                case 3:
                    Generic rating = data as Generic;
                    return rating.Movies;
            }
            return new List<Movie>();
        }

        public bool SupportsWatched()
        {
            return false;
        }

        #endregion
    }
}
